package com.sanji.pay.allinpay.web;

import com.alibaba.fastjson.JSON;
import com.sanji.pay.allinpay.entity.AllinPay;
import com.sanji.pay.allinpay.entity.Refund;
import com.sanji.pay.allinpay.service.AllinPayService;
import com.sanji.pay.allinpay.service.RefundService;
import com.sanji.pay.allinpay.util.QRCodeUtil;
import com.sanji.pay.allinpay.util.SybPayService;
import com.sanji.pay.allinpay.util.SybUtil;
import com.sanji.pay.pay.entity.PayOrder;
import com.sanji.pay.pay.service.PayOrderService;
import com.sanji.pay.pay.vo.PayResult;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 通联支付(微信、支付宝扫码支付)
 * Created by cbh on 2017/8/26.
 */
@Controller
@RequestMapping("/api/allinPay")
public class AllinPayController {
  private Logger logger = Logger.getLogger(AllinPayController.class);

  @Autowired
  private AllinPayService allinPayService;
  @Autowired
  private SybPayService sybPayService;
  @Autowired
  private RefundService refundService;
  @Autowired
  private PayOrderService payOrderService;
  @Value("${allinpay.callback}")
  private String notifyUrl;
  @Value("${allinpay.appkey}")
  public String SYB_APPKEY;
  @Autowired
  private SimpMessagingTemplate messagingTemplate;

  static ScheduledThreadPoolExecutor stpe = null;

  /**
   * 调用通联支付请求
   * @param payType：支付类型(W01：微信扫码支付A01：支付宝扫码支付Q01：手机QQ扫码支付)
   * @param payNumber：支付号
   * @param model
   * @return
   * @throws Exception
   */
  @GetMapping("/pay")
  public String pay(String payType, String payNumber, Model model) throws Exception {
    PayResult payResult = new PayResult();
    try {
      AllinPay allinPay = allinPayService.findByPayNum(payNumber);
      if(allinPay !=null && "0000".equals(allinPay.getTrxStatus())){
        payResult.setCode("2");
        payResult.setMessage("您的订单已支付");
        model.addAttribute("result",payResult);
        return "payment/payment_result";
      }
      PayOrder payOrder = payOrderService.findByPayNumber(payNumber);
      allinPay=allinPay==null?new AllinPay():allinPay;
      allinPay.setTrxId("");
      allinPay.setPayNum(payNumber);
      allinPay.setTrxAmt(payOrder.getAmount());
      allinPay.setTrxCode(payType);
      allinPay.setTrxStatus("0");

      allinPayService.save(allinPay);
      //价格是重新计算还是使用传值
      model.addAttribute("payAmount", String.valueOf(payOrder.getAmount() / 100.00));
    }catch (Exception e){
      logger.error("暂时调用支付系统失败" + e.getMessage());
      payResult.setCode("2");
      payResult.setMessage("暂时调用支付系统失败");
      model.addAttribute("result",payResult);
      return "payment/payment_result";
    }
    /**
     * trxstatus
     * 0000：交易成功
     * 3045,3088：交易超时
     * 3008：余额不足
     * 3999：交易失败
     * 2008：交易处理中
     * 3050：交易已撤销
     */
    return "allinpay/rq_code";
  }

  /**
   * 远程调用获取返回信息生成图片二维码
   * @param payType
   * @param payNumber
   * @param response
   * @throws Exception
   */
  @GetMapping("/getImage")
  public void getImage(@RequestParam String payType, @RequestParam String payNumber, HttpServletResponse response) throws Exception {
    AllinPay allinPay = allinPayService.findByPayNum(payNumber);
    PayOrder payOrder = payOrderService.findByPayNumber(payNumber);
    long now = new Date().getTime();
    long create = payOrder.getCreateTime().getTime();
    Integer validTime =payOrder.getValidTime();
    //有效时间验证
    if (validTime !=null && now - create > (validTime*60000)){
      return;
    }
    //请求第三方生成支付信息，body名称应考虑为订单商品名称
    Map<String, String> map = sybPayService.pay(payOrder.getAmount(), payNumber, payType,payOrder.getVendorName(), "", "","",notifyUrl, "");
    if (map.containsKey("trxstatus")&&"0000".equals(map.get("trxstatus"))){
      //收银宝平台的交易流水号
      String trxid = map.get("trxid");
      //保存支付信息
      allinPay.setPayNum(payNumber);
      allinPay.setPayInfo(map.get("payinfo"));//扫码支付则返回二维码字符串，开发者自行转化为二维码
      allinPay.setTrxId(trxid);//收银宝平台的交易流水号
      allinPay.setTrxStatus("0");
      allinPay.setTrxCode(payType);
      allinPayService.save(allinPay);
      //定时执行交易查询任务
//      stpe = new ScheduledThreadPoolExecutor(5);
//      AllinPayTaskService allinPayQuery = new AllinPayTaskService(payNumber,trxid);
//      allinPayQuery.setSybPayService(sybPayService);
//      stpe.schedule(allinPayQuery,60, TimeUnit.SECONDS);

      //生成二维码
      response.setContentType("image/png");
      String imagesLogoPath= "/images/QRCode/qr_encode.png";
      QRCodeUtil.encode(map.get("payinfo"),imagesLogoPath, response.getOutputStream(),true);
    }
  }

  /**
   * 退款
   * @return
   */
  @PostMapping("/refund")
  public ResponseEntity refund(String payNumber, Integer amount){
    Refund refund = refundService.refund(payNumber,amount);
    Map<String,Object> result = new HashMap<>();
    if (refund == null){
      result.put("status","ERROR");
      return ResponseEntity.ok(result);
    }
    result.put("status","SUCCESS");
    result.put("result",refund);
    return ResponseEntity.ok(result);
  }

  /**
   * 撤销
   * @return
   */
  @PostMapping("/cancel")
  public ResponseEntity cancel(String payNumber){
    Refund refund = refundService.cancel(payNumber);
    Map<String,Object> result = new HashMap<>();
    if (refund == null){
      result.put("status","ERROR");
      return ResponseEntity.ok(result);
    }
    result.put("status","SUCCESS");
    result.put("result",refund);
    return ResponseEntity.ok(result);

  }
  /**
   * 通联支付回调，页面返回是通过websocket定时查询
   * @param request
   * @param response
   * @throws ServletException
   * @throws IOException
   */
  @PostMapping("/callback")
  public void allinpayCallBack(HttpServletRequest request, HttpServletResponse response, Model model) throws ServletException,IOException  {
    logger.info("==========接收到通知==========");
    request.setCharacterEncoding("gbk");//通知传输的编码为GBK
    response.setCharacterEncoding("gbk");
    TreeMap<String,String> params = getParams(request);//动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容
    PayResult payResult = new PayResult();
    try {
      boolean isSign = SybUtil.validSign(params, SYB_APPKEY);// 接受到推送通知,首先验签
      logger.info("验签结果:"+isSign);
      logger.info(JSON.toJSONString(params));
      //验签完毕进行业务处理
      if (isSign){
        //回调支付成功
        if (params.containsKey("trxstatus")&&"0000".equals(params.get("trxstatus"))){
          //判断是否多次回调通知，先查询订单状态是否支付
          String payNum = params.get("cusorderid");
          AllinPay allinPay = allinPayService.findByPayNum(payNum);
          if("0".equals(allinPay.getTrxStatus())){
            logger.info("查看是否保存了签名信息" + params.get("sign"));
            allinPay.setTrxSign(params.get("sign"));
            allinPay = allinPayService.saveAlliPay(params,allinPay);
            payResult.setCode("1");
            payResult.setMessage("客官您已付款！我们会尽快安排发货，请耐心等待");
            //向商城返回支付成功或失败信息
            allinPayService.callbacktoMerchant(allinPay);
            /**
             * webSocker 通知客户端(client)
             * param 浏览器订阅的地址,对应--> stomp.subscribe
             * param 第三个参数是消息本身
             *
             */
            messagingTemplate.convertAndSend("/queue/notifications/"+payNum, "success");

          }else{

          }
        }else{
          payResult.setCode("2");
          payResult.setMessage("支付失败,请您重新进行支付");
          PayOrder payOrder = payOrderService.findByPayNumber(params.get("cusorderid"));
          payOrder.setStatus(PayOrder.PayStatus.FAILURE);
          payOrder.setDealType("allinPay");
          payOrderService.save(payOrder);
        }
      }
    } catch (Exception e) {//处理异常
      logger.info("订单支出现异常" + e.getMessage());
    }
  }

  /**
   * 返回成功页面
   * @param model
   * @return
   */
  @GetMapping("/result")
  public String result(Model model){
    PayResult payResult = new PayResult();
    payResult.setCode("1");
    payResult.setMessage("客官您已付款！我们会尽快安排发货，请耐心等待");
    model.addAttribute("result",payResult);
    return "payment/payment_result";
  }

  /**
   * 页面查询扫码支付是否成功
   * @return
   */
  @GetMapping("/{payNumber}")
  @ResponseBody
  public ResponseEntity findAllinPayStatus(@PathVariable("payNumber") String payNumber){
    AllinPay allinPay = allinPayService.findByPayNum(payNumber);
    return ResponseEntity.ok(allinPay);
  }

  /**
   * 动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容由于收银宝加字段而引起的签名异常
   * @param request
   * @return
   */
  private TreeMap<String, String> getParams(HttpServletRequest request){
    TreeMap<String, String> map = new TreeMap<String, String>();
    Map reqMap = request.getParameterMap();
    for(Object key:reqMap.keySet()){
      String value = ((String[])reqMap.get(key))[0];
      System.out.println(key+";"+value);
      map.put(key.toString(),value);
    }
    return map;
  }
}
